#pragma once

#define SQ_FAILED(res) (res<0)
#define SQ_SUCCEED(res) (res>=0)

#define SQ_VMSTATE_IDLE			0
#define SQ_VMSTATE_RUNNING		1
#define SQ_VMSTATE_SUSPENDED	2

#define SQUIRREL_EOB 0
#define SQ_BYTECODE_STREAM_TAG	0xFAFA

#define SQOBJECT_REF_COUNTED	0x08000000
#define SQOBJECT_NUMERIC		0x04000000
#define SQOBJECT_DELEGABLE		0x02000000
#define SQOBJECT_CANBEFALSE		0x01000000

#define SQ_MATCHTYPEMASKSTRING (-99999)

#define _RT_MASK 0x00FFFFFF
#define _RAW_TYPE(type) (type&_RT_MASK)

#define _RT_NULL			0x00000001
#define _RT_INTEGER			0x00000002
#define _RT_FLOAT			0x00000004
#define _RT_BOOL			0x00000008
#define _RT_STRING			0x00000010
#define _RT_TABLE			0x00000020
#define _RT_ARRAY			0x00000040
#define _RT_USERDATA		0x00000080
#define _RT_CLOSURE			0x00000100
#define _RT_NATIVECLOSURE	0x00000200
#define _RT_GENERATOR		0x00000400
#define _RT_USERPOINTER		0x00000800
#define _RT_THREAD			0x00001000
#define _RT_FUNCPROTO		0x00002000
#define _RT_CLASS			0x00004000
#define _RT_INSTANCE		0x00008000
#define _RT_WEAKREF			0x00010000

typedef enum class tagSQObjectType {
	OT_NULL = (_RT_NULL | SQOBJECT_CANBEFALSE),
	OT_INTEGER = (_RT_INTEGER | SQOBJECT_NUMERIC | SQOBJECT_CANBEFALSE),
	OT_FLOAT = (_RT_FLOAT | SQOBJECT_NUMERIC | SQOBJECT_CANBEFALSE),
	OT_BOOL = (_RT_BOOL | SQOBJECT_CANBEFALSE),
	OT_STRING = (_RT_STRING | SQOBJECT_REF_COUNTED),
	OT_TABLE = (_RT_TABLE | SQOBJECT_REF_COUNTED | SQOBJECT_DELEGABLE),
	OT_ARRAY = (_RT_ARRAY | SQOBJECT_REF_COUNTED),
	OT_USERDATA = (_RT_USERDATA | SQOBJECT_REF_COUNTED | SQOBJECT_DELEGABLE),
	OT_CLOSURE = (_RT_CLOSURE | SQOBJECT_REF_COUNTED),
	OT_NATIVECLOSURE = (_RT_NATIVECLOSURE | SQOBJECT_REF_COUNTED),
	OT_GENERATOR = (_RT_GENERATOR | SQOBJECT_REF_COUNTED),
	OT_USERPOINTER = _RT_USERPOINTER,
	OT_THREAD = (_RT_THREAD | SQOBJECT_REF_COUNTED),
	OT_FUNCPROTO = (_RT_FUNCPROTO | SQOBJECT_REF_COUNTED),
	OT_CLASS = (_RT_CLASS | SQOBJECT_REF_COUNTED),
	OT_INSTANCE = (_RT_INSTANCE | SQOBJECT_REF_COUNTED | SQOBJECT_DELEGABLE),
	OT_WEAKREF = (_RT_WEAKREF | SQOBJECT_REF_COUNTED)
}SQObjectType;

using HSQUIRRELVM = UINT*;
using SQFUNCTION = INT(*)(HSQUIRRELVM);

UINT registerFunction(PCWCHAR funName, SQFUNCTION sqfunc);

inline HSQUIRRELVM sq_getvm()
{
	return (HSQUIRRELVM)readVal(0x1AF3544);
}

using _sq_pushroottable = void(*)(HSQUIRRELVM v);
const _sq_pushroottable sq_pushroottable = (_sq_pushroottable)0x1358C50;

using _sq_getstring = INT(*)(HSQUIRRELVM v, INT idx, PCWCHAR* c);
const _sq_getstring sq_getstring = (_sq_getstring)0x1358E70;

using _sq_pushstring = void(*)(HSQUIRRELVM v, PCWCHAR s, INT len);
const _sq_pushstring sq_pushstring = (_sq_pushstring)0x1358A60;

using _sq_getinteger = INT(*)(HSQUIRRELVM v, INT idx, INT* i);
const _sq_getinteger sq_getinteger = (_sq_getinteger)0x1358D70;

using _sq_pushinteger = void(*)(HSQUIRRELVM v, INT n);
const _sq_pushinteger sq_pushinteger = (_sq_pushinteger)0x1358AD0;

using _sq_newclosure = void(*)(HSQUIRRELVM v, SQFUNCTION func, UINT freevars);
const _sq_newclosure sq_newclosure = (_sq_newclosure)0x135B850;

using _sq_newslot = INT(*)(HSQUIRRELVM v, INT idx, UINT bstatic);
const _sq_newslot sq_newslot = (_sq_newslot)0x135AA80;

using _sq_poptop = void(*)(HSQUIRRELVM v);
const _sq_poptop sq_poptop = (_sq_poptop)0x1358FF0;

using _sq_gettop = INT(*)(HSQUIRRELVM v);
const _sq_gettop sq_gettop = (_sq_gettop)0x1358FC0;

using _sq_throwerror = INT(*)(HSQUIRRELVM v, PCWCHAR s);
const _sq_throwerror sq_throwerror = (_sq_throwerror)0x13591A0;

using _sqstd_dofile = INT(*)(HSQUIRRELVM v, PCWCHAR fn, INT retval, INT printerror);
const _sqstd_dofile sqstd_dofile = (_sqstd_dofile)0x1356240;

using _sq_gettype = SQObjectType(*)(HSQUIRRELVM v, INT idx);
const _sq_gettype sq_gettype = (_sq_gettype)0x1358CD0;
